package org.proteored.miapeapi.xml.pride;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.log4j.Logger;
import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.exceptions.WrongXMLFormatException;
import org.proteored.miapeapi.interfaces.ms.MiapeMSDocument;
import org.proteored.miapeapi.interfaces.msi.MiapeMSIDocument;
import org.proteored.miapeapi.interfaces.xml.MiapePrideXmlFile;
import org.proteored.miapeapi.interfaces.xml.PrideXmlFactory;
import org.proteored.miapeapi.xml.pride.adapter.ExperimentCollectionAdapter;
import org.proteored.miapeapi.xml.pride.autogenerated.ExperimentCollection;

/**
 * Class that gives the method to create a PRIDE file from a MIAPE MS and/or MSI
 * document
 * 
 * @author Salvador
 * 
 */
public class PrideXmlFactoryImpl implements PrideXmlFactory {

	private static PrideXmlFactoryImpl instance;
	private static Logger log = Logger.getLogger("log4j.logger.org.proteored");
	private JAXBContext jc;
	private final boolean gelBasedExperiment;

	private PrideXmlFactoryImpl() {
		this(false);
	}

	private PrideXmlFactoryImpl(boolean gelBasedExperiment) {
		try {
			this.gelBasedExperiment = gelBasedExperiment;
			jc = JAXBContext
					.newInstance("org.proteored.miapeapi.xml.pride.autogenerated");

		} catch (JAXBException e) {
			e.printStackTrace();
			log.error(e);
			throw new WrongXMLFormatException(e);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e);

			throw new WrongXMLFormatException(e);
		}
	}

	/**
	 * Gets an instance of the class
	 * 
	 * @return a PrideXmlFactoryImpl object
	 */
	public static PrideXmlFactoryImpl getFactory() {
		if (instance == null) {
			instance = new PrideXmlFactoryImpl();
		}
		return instance;
	}

	public static PrideXmlFactoryImpl getFactory(boolean gelBasedExperiment) {
		if (instance == null
				|| !String.valueOf(instance.gelBasedExperiment).equals(
						String.valueOf(gelBasedExperiment))) {
			instance = new PrideXmlFactoryImpl(gelBasedExperiment);
		}
		return instance;
	}

	/**
	 * Creates a PRIDE file from a MIAPE MS and/or MSI documents
	 * 
	 * @param miapeMS
	 *            MIAPE MS document
	 * @param miapeMSI
	 *            MIAPE MSI document
	 * @param cvManager
	 * @param xmlFile
	 * @param parseMGF
	 *            state if extract peakList information from the resulting data
	 *            section of the MIAPE MS
	 * @return A PRIDE XML file
	 */
	@Override
	public MiapePrideXmlFile toXml(MiapeMSDocument miapeMS,
			MiapeMSIDocument miapeMSI, ControlVocabularyManager cvManager,
			MiapePrideXmlFile xmlFile, boolean parseResultingDataPeakList) {
		if (cvManager == null)
			throw new IllegalMiapeArgumentException(
					"ControlVocabularyManager is not set");
		try {
			log.info("creating PRIDE XML");
			Marshaller marshaller = jc.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
					new Boolean(true));
			ExperimentCollection experimentCollection = new ExperimentCollectionAdapter(
					miapeMS, miapeMSI, cvManager, parseResultingDataPeakList,
					gelBasedExperiment).adapt();
			log.info("adapted to XML: " + experimentCollection);
			marshaller.marshal(experimentCollection, xmlFile.toFile());
			log.info("created file");
		} catch (JAXBException e) {
			e.printStackTrace();
			log.error(e);
			throw new WrongXMLFormatException(
					"error: The files does not seem to have PRIDE Format");
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e);
			throw new WrongXMLFormatException(e);
		}
		return xmlFile;
	}
}
